org  07c00h

%include "include/load.inc"

;宏定义
BaseOfStack		        equ	07c00h  ;堆栈低
RootDirSectors		    equ	14	    ;
SectorNoOfRootDirectory	equ	19
SectorNoOfFAT1          equ 1
DeltaSectorNo           equ 17


	jmp short LABEL_START		    ; Start to boot.
	nop				                ; 这个 nop 不可少

	; 下面是 FAT12 磁盘的头
	BS_OEMName	    DB 'ForrestY'	    ; OEM String, 必须 8 个字节
	BPB_BytsPerSec	DW 512		        ; 每扇区字节数
	BPB_SecPerClus	DB 1		        ; 每簇多少扇区
	BPB_RsvdSecCnt	DW 1		        ; Boot 记录占用多少扇区
	BPB_NumFATs	    DB 2		        ; 共有多少 FAT 表
	BPB_RootEntCnt	DW 224		        ; 根目录文件数最大值
	BPB_TotSec16	DW 2880		        ; 逻辑扇区总数
	BPB_Media	    DB 0xF0		        ; 媒体描述符
	BPB_FATSz16	    DW 9		        ; 每FAT扇区数
	BPB_SecPerTrk	DW 18		        ; 每磁道扇区数
	BPB_NumHeads	DW 2		        ; 磁头数(面数)
	BPB_HiddSec	    DD 0		        ; 隐藏扇区数
	BPB_TotSec32	DD 0		        ; 如果 wTotalSectorCount 是 0 由这个值记录扇区数
	BS_DrvNum	    DB 0		        ; 中断 13 的驱动器号
	BS_Reserved1	DB 0		        ; 未使用
	BS_BootSig	    DB 29h		        ; 扩展引导标记 (29h)
	BS_VolID	    DD 0		        ; 卷序列号
	BS_VolLab	    DB 'OrangeS0.02'    ; 卷标, 必须 11 个字节
	BS_FileSysType	DB 'FAT12   '	    ; 文件系统类型, 必须 8个字节  

LABEL_START:	
	mov	ax, cs
	mov	ds, ax
	mov	es, ax
	mov	ss, ax
	mov	sp, BaseOfStack

	; 清屏
	mov	ax, 0600h		; AH = 6,  AL = 0h
	mov	bx, 0700h		; 黑底白字(BL = 07h)
	mov	cx, 0			; 左上角: (0, 0)
	mov	dx, 0184fh		; 右下角: (80, 50)
	int	10h			; int 10h

    mov	dh, 0			; "Booting  "
	call	DispStr

    ;复位A盘
    xor ah, ah
    xor dl, dl
    int 13h

    mov word [wSectorNo], SectorNoOfRootDirectory
LABEL_SEARCH_IN_ROOT_DIR_BEGIN:
    cmp word [wRootDirSizeForLoop], 0
    jz LABEL_NO_LOADERBIN 
    dec word [wRootDirSizeForLoop]
    mov ax, BaseOfLoader
    mov es, ax
    mov bx, OffsetOfLoader
    mov ax, [wSectorNo]
    mov cl, 1
    call ReadSector
	
	mov si, LoaderFileName
	mov di, OffsetOfLoader
	cld
	mov dx, 10h ;一共扇区内有16个项
LABEL_SEARCH_FOR_LOADERBIN:
	cmp	dx, 0
	jz LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR
	dec dx
	mov cx, 11 ;待比较的字符串长度
LABEL_CMP_FILENAME:
	cmp cx, 0
	jz LABEL_FILENAME_FOUND
	dec cx
	lodsb
	cmp al, byte [es:di]
	jz LABEL_GO_ON
	jmp	LABEL_DIFFERENT
LABEL_GO_ON:
	inc di
	jmp LABEL_CMP_FILENAME
LABEL_DIFFERENT:
	and di, 0FFE0h
	add di, 20h
	mov si, LoaderFileName
	jmp LABEL_SEARCH_FOR_LOADERBIN
LABEL_GOTO_NEXT_SECTOR_IN_ROOT_DIR:
	add word [wSectorNo],1
	jmp LABEL_SEARCH_IN_ROOT_DIR_BEGIN

LABEL_NO_LOADERBIN:
	mov dh, 2
	call DispStr
	jmp $

LABEL_FILENAME_FOUND:
	mov dh, 1
	call DispStr
	
	mov ax, RootDirSectors
	and di, 0FFE0h
	add di, 01Ah
	mov cx, word [es:di]	;得到FAT序号，也是
	push cx					;保存FAT序号
	add cx, ax
	add cx, DeltaSectorNo
	mov ax, BaseOfLoader
	mov es, ax
	mov bx, OffsetOfLoader
	mov ax, cx

LABEL_GOON_LOADING_FILE:
	mov cl, 1
	call ReadSector
	pop ax					;取出FAT序号
	call GetFATEntry
	cmp ax, 0FFFh
	jz LABEL_FILE_LOADED
	push ax
	mov dx, RootDirSectors
	add ax, dx
	add ax, DeltaSectorNo;计算下一个扇区号
	add bx, [BPB_BytsPerSec]	;移动目的内存指针
	jmp LABEL_GOON_LOADING_FILE
LABEL_FILE_LOADED:
	mov dh, 3
	call DispStr
	jmp BaseOfLoader:OffsetOfLoader ;跳转Loader

wRootDirSizeForLoop     dw RootDirSectors
wSectorNo               dw 0
event                   dw 0 

LoaderFileName		    db "LOADER  BIN", 0
MessageLength		equ	9
BootMessage:		    db "Booting  "
Message1		        db "LOADING. "
Message2		        db "No LOADER"
Message3		        db "Ready    "

;这里涉及到软盘中扇区的安排
;同一个柱面交替读写上下两个面
;
ReadSector:
    push bp
    mov bp, sp
    sub esp, 2

    mov byte [bp-2], cl
    push bx
    mov bl, [BPB_SecPerTrk]
    div bl
    inc ah
    mov cl, ah	;求得物理的扇区号
    mov dh, al
    shr al, 1
    mov ch, al	;求得柱面
    and dh, 1	;求得磁头号
    pop bx
	mov	dl, [BS_DrvNum]
.GoOnReading:
	mov ah, 2
	mov al, byte [bp-2]
	int 13h
	jc .GoOnReading

	add esp, 2	;清除堆栈中的局部变量
	pop bp

	ret

; @para ax[in] 序号位ax的FAT条目
; @ret 	ax[out] 对应的下一个条目

GetFATEntry:
	push es
	push bx
	push ax

	mov ax, BaseOfLoader
	sub ax, 0100h
	mov es, ax
	pop ax
	mov byte [event], 0
	mov bx, 3
	mul bx 
	mov bx, 2
	div bx
	cmp dx, 0
	jz LABEL_EVENT
	mov byte [event], 1
LABEL_EVENT:
	xor dx, dx
	mov bx, [BPB_BytsPerSec]
	div bx
	push dx
	mov bx, 0
	add ax, SectorNoOfFAT1
	mov cl,2
	call ReadSector
	pop dx
	add bx, dx
	mov ax, [es:bx]
	cmp byte [event],1
	jnz LABEL_EVENT_2
	shr ax, 4
LABEL_EVENT_2:
	and ax,0FFFh

	pop	bx
	pop	es
	ret
DispStr:
	push es
	mov	ax, MessageLength
	mul	dh
	add	ax, BootMessage
	mov	bp, ax
	mov	ax, ds
	mov	es, ax
	mov	cx, MessageLength
	mov	ax, 01301h
	mov	bx, 0007h
	mov	dl, 0
	int	10h
	pop es
	ret

times 	510-($-$$)	db	0	; 填充剩下的空间，使生成的二进制代码恰好为512字节
dw 	0xaa55					; 结束标志